<?php
class ReflectionClassEx extends ReflectionClass
{
	/******Overrides******/

	private $properties = array();

	public function ReflectionClassEx( $class )
	{
		$this->reflection = new ReflectionClass( $class );
		$this->initializeHandlers();
		$this->parseClass();
	}

	public function __get( $name )
	{
		$return = null;

		if ( isset($this->properties[$name]) ) {
			$return = $this->properties[$name];
		}

		return( $return );
	}

    public function __set( $name, $value )
	{
		$this->properties[$name] = $value;
    }

	public function __call( $name, $arguments )
	{
		return( call_user_method_array( $name, $this->reflection, $arguments ) );
	}

	/*********************/

	private $reflection;

	private $handlerClasses = array (
		"AnnotationHandler"
	);

	private $reflectionHandler = array ();

	private $reflectObjects = array();


	/**
	 * Analiza esta clase y le pasa los datos a cada
	 * controlador de reflexión existente, para crear
	 * la extensión de la funcionalidad de Reflection.
	 */
	private function parseClass()
	{
		$file = file( $this->reflection->getFileName() );

		for( $i = 0; $i < count($file); $i++ )
		{
			$line = $file[$i];

			foreach( $this->reflectionHandler as $key => $handler )
			{
				// Verifica si la línea contiene datos que
				// puede manipular el handler.
				//
				if( $handler->matchExpression( $line ) )
				{

					// Ejecuta el controlador.
					//
					$reflectionObj = $handler->execute( $line );

					$property = $handler->getHandlerName();

					if ( !is_array($this->reflectObjects[$property] ) )
					{
						$this->reflectObjects[$property] = array();
					}

					array_push($this->reflectObjects[$property], $reflectionObj);
				}
			}
		}
	}

	/**
	 * Inicializa los controladores de reflección
	 * configurados en la propiedad reflectionHandler.
	 */
	private function initializeHandlers()
	{
		foreach( $this->handlerClasses as $key => $handler )
		{
			if( class_exists( $handler ) )
			{
				$this->reflectionHandler[ $handler ] = new $handler();
			}
		}
	}

	private function getReflectionObjects( $handlerName )
	{
		if ( isset( $this->reflectObjects[$handlerName] ) )
		{
			return( $this->reflectObjects[$handlerName] );
		}

		return(null);
	}

	/************ Funciones de Reflection **************/

	/**
	 * Devuelve todas las anotaciones de esta clase.
	 */
	public function getAnnotations()
	{
		$property = "annotation";

		$objects = $this->getReflectionObjects( $property );

		return( $objects );
	}

	public function getDeclaredAnnotation( $class )
	{
		$objects = $this->getAnnotations();
		$annot = array();

		for( $i = 0; $i < count($objects); $i++ )
		{
			$item = $objects[$i];

			if ( get_class($item) == $class ) {
				array_push( $annot, $item );
			}
		}

		if ( count($annot) == 1 ) {
			$annot = $annot[0];
		}

		return( $annot );
	}

	/***************************************************/
}
?>
